use std::env;
use std::path::PathBuf;

use config::{Config, File};
use log::info;

use crate::Error;

#[cfg(test)]
mod tests;

pub(crate) fn load(
    config_file_path: Option<String>,
    tile_directory: Option<String>,
) -> Result<Config, Error> {
    let config_file_path = config_file_path.map(PathBuf::from);
    let mut config = Config::builder();

    if let Some(path) = config_file_path.clone() {
        config = config.add_source(File::from(path));
    }

    // Override config.tile_directory with tile_directory, if Some.
    config = config.set_override_option("tile_directory", tile_directory)?;

    // Build the configuration cloned just to see whether config.tile_directory is
    // unset.
    if config.build_cloned()?.get_string("tile_directory").is_err() {
        // Apparently config.tile_directory is unset, so set a sensible value.
        let path = if let Some(file_path) = config_file_path {
            let directory = file_path
                .parent()
                .expect("the configuration file should have a parent directory")
                .to_string_lossy()
                .to_string();
            info!(
                "No tile directory provided; assuming configuration file directory {}",
                directory
            );
            directory
        } else {
            let current_dir = match env::current_dir() {
                Ok(directory) => directory.to_string_lossy().to_string(),
                Err(io_error) => {
                    return Err(Error::IoError(format!(
                        "the current working directory could not be accessed: {}",
                        io_error
                    )))
                },
            };
            info!(
                "No tile directory provided; assuming current working directory {}",
                current_dir
            );
            current_dir
        };
        config = config.set_override("tile_directory", path)?;
    }

    Ok(config.build()?)
}
